
package v2store

type Watcher interface {
	EventChan() chan *Event
	StartIndex() uint64 // 创建观察者的EtcdIndex 
	Remove()
}

// watcher是客户端用来监听etcd服务端数据变化的一种手段，
// 在客户端对指定路径节点添加watcher之后，
// 如果该节点数据发生变化，则etcd服务端会通知相应的客户端。
type watcher struct {
	// 当该watcher实例被修改操作触发时，会将对应的Event实例写入到该通道中，
	// 后续由网络层读取该通道，并通知客户端此次修改。
	eventChan  chan *Event
	// 标识当前watcher是否为stream类型的，当前由earnwatcher被触发一次后，
	// 并不会被自动删除，而是继续保持监昕，井返回一系列监听到的Event。
	stream     bool
	// 标识当前watcher实例是否监听目标节点的子节点。
	recursive  bool
	// 标识该watcher实例从哪个Currentlndex值开始监听对应的节点。
	sinceIndex uint64
	// 记录创建该watcher实例时对应的Currentlndex值。
	startIndex uint64
	// 在watcherHub中维护了该watcher实例与其监听的节点路径的映射关系，
	hub        *watcherHub
	// 标记当前watcher实例是否己经被删除。
	removed    bool
	// 用于删除当前watcher实例的回调函数
	remove     func()
}

func (w *watcher) EventChan() chan *Event {
	return w.eventChan
}

func (w *watcher) StartIndex() uint64 {
	return w.startIndex
}

// notify（）方法，该方法负责将触发该watcher的Event实例写入eventChan通道中，
// 在如下三种场景下当前watcher会被触发：
// 当修改操作发生在当前watcher实例监昕的节点上时，会触发该watcher实例。
// 当前watcher实例不仅监听当前节点的变化，同时也监昕其子节点的变化，
//     当修改操作发生在子节点上时，也会触发该watcher实例。
// 当删除某个目录节点时，需要通知在其子节点上监听的全部watcher实例。
func (w *watcher) notify(e *Event, originalPath bool, deleted bool) bool {
	if (w.recursive ||	// 检查当前watcher是否监听对应节点的子节点
		originalPath ||	// 检查发生变化的是否正好是当前watcher监听节点
		deleted) && 	// 检查此次修改操作是否为删除操作
		e.Index() >= w.sinceIndex {	// 检查操作发生的时机是否为该watcher监听的范围
		select {
		case w.eventChan <- e:	// 将修改操作对应的Event写入eventChan遥远等待处理
		default:
			w.remove()	// 如果当前watcher.eventChan通道被填充满了，则会将该通道关闭，这可能导致事件丢失
		}
		return true
	}
	return false
}

// Remove从watcher中删除观察者Hub 
// 保证只执行一次实际的删除函数
func (w *watcher) Remove() {
	w.hub.mutex.Lock()
	defer w.hub.mutex.Unlock()

	close(w.eventChan)
	if w.remove != nil {
		w.remove()
	}
}

// NoWatcher是一个不接收任何内容的观察者，总是阻塞。
type nopWatcher struct{}

func NewNopWatcher() Watcher                 { return &nopWatcher{} }
func (w *nopWatcher) EventChan() chan *Event { return nil }
func (w *nopWatcher) StartIndex() uint64     { return 0 }
func (w *nopWatcher) Remove()                {}
